#include <iostream>
#include <algorithm>
#include <jsoncpp/json/json.h>
#include "index.hpp"

namespace ns_search
{
    class Searcher
    {
    private:
        ns_index::index *ind; // 索引对象指针

    public:
        Searcher(){};
        ~Searcher(){};

    public:
        void InitSearch(const std::string &input)
        {
            // 获取或创建索引对象
            ind = ns_index::index::CreateIndex();
            std::cout << "创建索引对象成功" << std::endl;
            // 构建正倒排索引
            ind->BuildIndex(input);
        }

        // 获取查询的单词
        void Search(const std::string &query, std::string *json_string)
        {
            // 对搜索词进行jieba分词
            std::vector<std::string> words;
            ns_ntil::JiebaUtil::CutString(query, &words);

            // 使用倒排索引查询doc_id
            // 保存倒排索引查询出的倒排拉链的全部集合
            std::vector<ns_index::InvertedElem> inverted_list;
            for (auto &word : words)
            {
                // 把大写改为小写统一查询
                boost::to_lower(word);
                // 使用倒排索引进行查询，把查询的倒排拉链指针返回
                std::vector<ns_index::InvertedElem> *doc = ind->GetInvertedList(word);
                if (doc == nullptr)
                {
                    continue;
                }
                // 将倒排拉链的内容全部放入inverted_list
                inverted_list.insert(inverted_list.end(), doc->begin(), doc->end());

                // 有过多单词索引的同一篇文章，需要进行合并
            }
            // 对inverted_list进行排序
            if (inverted_list.size() == 0)
            {
                std::cout << "没有找到" << std::endl;
                return;
            }

            sort(inverted_list.begin(), inverted_list.end(),
                 [](const ns_index::InvertedElem &s1, const ns_index::InvertedElem &s2)
                 { return s1.weight > s2.weight; });

            Json::Value root;
            // 根据倒排拉链的集合doc_id进行正排索引
            for (auto &inverted : inverted_list)
            {
                ns_index::DockInFo *d = ind->GetForwardIndex(inverted.doc_id);
                if (d == nullptr)
                {
                    continue;
                }

                // 根据正排索引的doc_id索引文档并返回
                // 使用Json对内容进行返回
                Json::Value item;
                item["title"] = d->title;
                item["content"] = GetDesc(d->content, inverted.word); // 内容太长，进行关键字前50，后100字节的获取
                item["url"] = d->url;
                item["weight"] = inverted.weight;
                root.append(item);
            }
            Json::StyledWriter writer;
            *json_string = writer.write(root);
        }

    public:
        std::string GetDesc(const std::string &con, const std::string &word)
        {
            // 这里是因为倒排索引结构体的内容都是转换成小写的，但是正排索引结构体并没有转为小写
            // 要进行大小写匹配
            std::string content = con;
            boost::to_lower(content);

            const size_t prev = 50;
            const size_t next = 100;
            // 找到第一次出现word的前五十和后100个字并提取
            size_t pos = content.find(word);
            if (pos == std::string::npos)
            {
                return "No find";
            }
            size_t start = 0, end = content.size() - 1;

            // if (pos - prev > start)//这里会有问题，size_t是无符号整形，<0时会变成最大值，导致错误
            //     start = pos - prev;
            if (pos > prev)
                start = pos - prev;
            if (pos + next < end)
                end = pos + next;

            // 获取子串
            return con.substr(start, end - start);
        }
    };
}
